package org.example.erp.web.manager;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.example.erp.domain.SysMenu;
import org.example.erp.mapper.SysMenuMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.function.Supplier;
/*
 * @Date 2024-10-10
 * @Author 28254
 * @ClassName MyAuthorizationManager
 * 自定义复杂匹配规则，动态权限实现
 * 实现思路：
 * 1. 查询当前访问接口所需要的权限，并且根据当前认证用户所拥有的权限判断是否包含接口所需权限
 * 2. 对访问资源路径进行权限的控制 例如接口路径：/api/user/list <=> 权限映射 sys:user:list 访问用户列表
 * 3. 获取用户权限集合标识和数据库权限标识匹配
 * 4. 优化：可以把数据库操作查询结果放到redis中减少数据库压力
*/
@Component
public class MyAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    private final SysMenuMapper sysMenuMapper;

    @Autowired
    public MyAuthorizationManager(SysMenuMapper sysMenuMapper) {
        this.sysMenuMapper = sysMenuMapper;
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
        // 获取uri 登录相关不需要权限
        String requestURI = object.getRequest().getRequestURI().trim();
        System.out.println(requestURI);

        if("/api/user/login".equals(requestURI) || "/api/loginLog/insert".equals(requestURI)) {
            return new AuthorizationDecision(true);
        }
        // 根据uri路径匹配菜单项
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("url", requestURI);
        SysMenu menu = sysMenuMapper.selectOne(queryWrapper);
        if (menu == null) {
            return new AuthorizationDecision(false);
        }
        // 得到菜单项中的权限
        String perms = menu.getPerms();
//         如果为空，则表示目录或菜单不需要权限
        if(perms == null || perms.trim().isEmpty()){
            return new AuthorizationDecision(true);
        }
        // 到这步 则需要验证权限, 从当前用户的认证信息中获取角色或权限信息
        Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
        for (GrantedAuthority authority : authorities) {
            // 比对用户是否有该权限,当用户不是登录过来授权的，会是一个匿名用户和权限
            String userAuthority = authority.getAuthority();
            if(userAuthority.equals(perms)){
                return new AuthorizationDecision(true);
            }
        }
        return new AuthorizationDecision(false);
    }
}
